package cn.wen.yaling.xo.service.impl;

import cn.wen.yaling.commons.constant.RedisConstants;
import cn.wen.yaling.commons.entity.ExceptionLogEntity;
import cn.wen.yaling.commons.entity.PermissionEntity;
import cn.wen.yaling.commons.enums.LogStatus;
import cn.wen.yaling.commons.enums.MenuStatus;
import cn.wen.yaling.commons.enums.MenuType;
import cn.wen.yaling.commons.service.RedisService;
import cn.wen.yaling.commons.utils.*;
import cn.wen.yaling.commons.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.awt.*;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.wen.yaling.xo.dao.MenuDao;
import cn.wen.yaling.commons.entity.MenuEntity;
import cn.wen.yaling.xo.service.MenuService;


@Slf4j
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuDao, MenuEntity> implements MenuService {

    @Autowired
    private MenuDao menuDao;

    @Autowired
    private RedisService redisService;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<MenuEntity> page = this.page(
                new Query<MenuEntity>().getPage(params),
                new QueryWrapper<MenuEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public List<NavigationBarVO> menuListBySort() {
        List<NavigationBarVO> navigations;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_BAR_LIST)) {
            navigations = redisUtils.getListCache(RedisConstants.CACHE_BAR_LIST, NavigationBarVO.class);
            log.info("缓存数据：{}", navigations);
        } else {
            // 2、缓存不命中则到db中获取
            navigations = menuDao.menuListByPriority();
            for (NavigationBarVO navigationBarVO : navigations) {
                if (navigationBarVO.getId() == 2) {
                    navigationBarVO.setChildNar(menuDao.listSubjectByPriority());
                }
            }
            log.info("数据库数据：{}", navigations);
            // 3、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_BAR_LIST, navigations);
        }
        return navigations;
    }

    @Override
    public ResultEntity getMenuList() {
        List<MenuVO> menuList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_ADMIN_MENU_LIST)) {
            menuList = redisUtils.getListCache(RedisConstants.CACHE_ADMIN_MENU_LIST, MenuVO.class);
        } else {
            // 2、缓存不命中则到db中获取
            QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("is_back", true);
            menuList = getAllMenuList(queryWrapper);
            // 3、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_ADMIN_MENU_LIST, menuList);
        }
        return ResultEntity.ok().put("data", menuList);
    }

    private List<MenuVO> getAllMenuList(QueryWrapper<MenuEntity> queryWrapper) {
        queryWrapper.eq("menu_status", MenuStatus.NORMAL_USE.getStatus());
        queryWrapper.eq("menu_level", 1);
        queryWrapper.eq("menu_type", MenuType.MENU);
        queryWrapper.orderByAsc("menu_sort");
        List<MenuEntity> menuEntities = menuDao.selectList(queryWrapper);

        List<Integer> ids = new ArrayList<>();
        // 获取所有的父菜单
        menuEntities.forEach(item -> {
            if (item.getId() != 0) {
                ids.add(item.getId());
            }
        });

        // 寻找子类
        QueryWrapper<MenuEntity> childWrapper = new QueryWrapper<>();
        childWrapper.in("parent_id", ids);
        childWrapper.eq("menu_status", MenuStatus.NORMAL_USE.getStatus());
        childWrapper.eq("menu_type", MenuType.MENU);

        // 全部的
        Collection<MenuEntity> childList = menuDao.selectList(childWrapper);

        List<MenuVO> list = new ArrayList<>();
        getMenuVoList(childList, menuEntities, list);
        return list;
    }

    @Override
    public ResultEntity addMenu(MenuAddVO menuAddVO) {
        MenuEntity target = new MenuEntity();
        BeanUtils.copyProperties(menuAddVO, target);
        target.setCreateTime(new Date());
        target.setMenuStatus(MenuStatus.NORMAL_USE.getStatus());
        target.setUpdateTime(new Date());
        boolean res = menuDao.insert(target) > 0;
        if (res) {
            // 删除菜单列表相关缓存
            redisUtils.delMenuListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity editMenu(MenuUpdateVO menuUpdateVO) {
        MenuEntity target = new MenuEntity();
        BeanUtils.copyProperties(menuUpdateVO, target);
        if (target.getIsShow()) {
            target.setMenuStatus(target.getIsShow() ? MenuStatus.NORMAL_USE.getStatus():
                    MenuStatus.FORBID.getStatus());
        }
        target.setUpdateTime(new Date());
        boolean res = menuDao.updateById(target) > 0;
        if (res) {
            // 删除菜单列表相关缓存
            redisUtils.delMenuListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity deleteMenu(Integer menuId) {
        MenuEntity target = new MenuEntity();
        target.setId(menuId);
        target.setMenuStatus(MenuStatus.DELETED.getStatus());
        boolean res = menuDao.updateById(target) > 0;
        if (res) {
            // 删除菜单列表相关缓存
            redisUtils.delMenuListCache();
            return ResultEntity.ok();
        }
        return ResultEntity.error();
    }

    @Override
    public ResultEntity getWebNavBarList() {
        List<MenuVO> menuList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_WEB_MENU_LIST)) {
            menuList = redisUtils.getListCache(RedisConstants.CACHE_WEB_MENU_LIST, MenuVO.class);
        } else {
            // 2、缓存不命中则到db中获取
            QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("is_back", false);
            menuList = getAllMenuList(queryWrapper);
            // 3、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_WEB_MENU_LIST, menuList);
        }
        return ResultEntity.ok().put("data", menuList);
    }

    @Override
    public ResultEntity getSimpleMenuList() {
        List<MenuSimpleVO> menuList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_ADMIN_LEVEL_MENU_LIST)) {
            menuList = redisUtils.getListCache(RedisConstants.CACHE_ADMIN_LEVEL_MENU_LIST, MenuSimpleVO.class);
        } else {
            // 2、缓存不命中则到db中获取
            QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("menu_level", 1);
            queryWrapper.eq("menu_type", 0);
            queryWrapper.eq("is_back", true);
            queryWrapper.eq("menu_status", MenuStatus.NORMAL_USE.getStatus());
            List<MenuEntity> menus = menuDao.selectList(queryWrapper);
            menuList = menus.stream().map(item -> {
                MenuSimpleVO target = new MenuSimpleVO();
                BeanUtils.copyProperties(item, target);
                return target;
            }).collect(Collectors.toList());
            // 3、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_ADMIN_LEVEL_MENU_LIST, menuList);
        }
        return ResultEntity.ok().put("data", menuList);
    }

    @Override
    public List<MenuVO> getMenuListByRoleId(Integer roleId) {
        // 1.首先获取所有的才到那
        List<MenuEntity> menuList = menuDao.getMenuByRoleId(roleId);
        // 2.通过Stream流获取父路径
        List<MenuEntity> parentList =
                menuList.stream().filter(item -> {
                    return item.getMenuLevel() == 1; // 保留父路径
                }).collect(Collectors.toList());
        List<MenuVO> list = new ArrayList<>();
        getMenuVoList(menuList, parentList, list);
        return list;
    }

    @Override
    public ResultEntity getMenuTreeList() {
        List<TreeVO> menuList;
        // 1、先判断redis缓存中是否能命中缓存
        if (redisService.hasKey(RedisConstants.CACHE_ADMIN_TREE_MENU_LIST)) {
            menuList = redisUtils.getListCache(RedisConstants.CACHE_ADMIN_TREE_MENU_LIST, TreeVO.class);
        } else {
            // 2、缓存不命中则到db中获取
            //  1.获取全部的一级目录
            List<MenuEntity> levelMenuList = getMenuListByParentId(0);
            //  2.获取到二级菜单
            menuList = new ArrayList<>();
            levelMenuList.forEach((item) -> {
                TreeVO target = new TreeVO();
                target.setId(item.getId());
                target.setName(item.getMenuName());
                List<MenuEntity> childList = getMenuListByParentId(item.getId());
                List<TreeVO> childs = new ArrayList<>();
                if (childList != null) {
                    childs = childList.stream().map((o) -> {
                        TreeVO childTarget = new TreeVO();
                        childTarget.setId(o.getId());
                        childTarget.setName(o.getMenuName());
                        return childTarget;
                    }).collect(Collectors.toList());
                }
                target.setChildren(childs);
                menuList.add(target);
            });
            // 3、将db中的缓存获取到
            redisUtils.setListCache(RedisConstants.CACHE_ADMIN_TREE_MENU_LIST, menuList);
        }
        return ResultEntity.ok().put("data", menuList);
    }

    private List<MenuEntity> getMenuListByParentId(Integer parentId) {
        QueryWrapper<MenuEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        queryWrapper.eq("menu_type", 0);
        queryWrapper.eq("is_back", true);
        queryWrapper.eq("menu_status", MenuStatus.NORMAL_USE.getStatus());
        List<MenuEntity> menus = menuDao.selectList(queryWrapper);
        return menus;
    }


    private void getMenuVoList(Collection<MenuEntity> menuList, List<MenuEntity> parentList, List<MenuVO> list) {
        for (MenuEntity parentItem : parentList) {
            List<MenuVO> tempList = new ArrayList<>();
            for (MenuEntity item : menuList) {

                if (item.getParentId() == parentItem.getId()) {
                    MenuVO target = new MenuVO();
                    BeanUtils.copyProperties(item, target);
                    tempList.add(target);
                }
            }
            Collections.sort(tempList);
            MenuVO menuVO = new MenuVO();
            BeanUtils.copyProperties(parentItem, menuVO);
            menuVO.setChildMenu(tempList);
            list.add(menuVO);
        }
    }


}